﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Web;
using System.IO;
using System.Drawing.Imaging;
using log4net;

namespace CodeWork.Library
{
    public class ImageResizer
    {
        /// <summary>
        /// Creates a thumbnail image from another image with the width and height
        /// specified. Helpful in case of creating a different sized thumbnail 
        /// image from the original image.
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path of the output image where to create the thumbnail. This includes the output filename.</param>
        /// <param name="width">Desired width of the thumbnail image</param>
        /// <param name="height">Desired height of the thumbnail image</param>
        /// <param name="addSufix">If true, an extension is added to differentiate from the original image</param>
        /// <param name="sufix">The sufix to be be added in output filename, if not supplied, _thumb will be used.</param>
        /// <returns>True if the thumbnail is successfuly created, false otherwise</returns>
        public static bool CreateThumbnail(string parentImageFilePath, string outputImageFilePath, int width, int height, bool addSufix, string sufix)
        {
            try
            {
                // Trying to locate the original image file
                FileInfo parentImageFile = new FileInfo(HttpContext.Current.Server.MapPath(parentImageFilePath));
                if (parentImageFile.Exists)
                {
                    if (string.IsNullOrEmpty(sufix))
                        sufix = "_thumb";

                    // Adding the sufix to the filename
                    if (addSufix)
                        outputImageFilePath = (parentImageFile.Name.Insert(parentImageFile.Name.IndexOf('.') - 1, sufix));

                    // Deleting if the file already exists.
                    if (File.Exists(outputImageFilePath))
                        FileAccessUtility.DeleteFile(outputImageFilePath);

                    // Loading the image from image file
                    using (Image parentImage = Image.FromFile(parentImageFile.FullName))
                    {
                        // Creating the thumbnail and saving it 
                        Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);
                        thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath), parentImage.RawFormat);
                        return true;
                    }
                }
                else
                    return false;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Create thumbnail caused server error: Parameters( ");
                logText = logText.Append("parentImageFilePath -> ").Append(parentImageFilePath);
                logText = logText.Append("outputImageFilePath -> ").Append(outputImageFilePath);
                logText = logText.Append("width -> ").Append(width.ToString());
                logText = logText.Append("height -> ").Append(height.ToString());
                logText = logText.Append("addSufix -> ").Append(addSufix.ToString());
                logText = logText.Append("sufix -> ").Append(sufix);
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("ImageResizer");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        /// <summary>
        /// Creates a thumbnail image from another image with the width 
        /// specified. Helpful in case of creating a different sized thumbnail 
        /// image from the original image. This method overwrites if the file
        /// already exists.
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path of the output image where to create the thumbnail. This includes the output filename.</param>
        /// <param name="width">Desired width of the thumbnail image</param>
        /// <param name="addSufix">If true, an extension is added to differentiate from the original image</param>
        /// <param name="sufix">The sufix to be be added in output filename, if not supplied, _thumb will be used.</param>
        /// <returns>True if the thumbnail is successfuly created, false otherwise</returns>
        public static bool CreateThumbnail(string parentImageFilePath, string outputImageFilePath, int width, bool addSufix, string sufix)
        {
            try
            {
                // Trying to locate the original image file
                FileInfo parentImageFile = new FileInfo(HttpContext.Current.Server.MapPath(parentImageFilePath));
                if (parentImageFile.Exists)
                {
                    if (string.IsNullOrEmpty(sufix))
                        sufix = "_thumb";

                    // Adding the sufix to the filename
                    if (addSufix)
                        outputImageFilePath = parentImageFile.Name.Insert(parentImageFile.Name.IndexOf('.') - 1, sufix);

                    // Deleting if the file already exists.
                    if (File.Exists(outputImageFilePath))
                        FileAccessUtility.DeleteFile(outputImageFilePath);

                    // Loading the image from image file
                    using (Image parentImage = Image.FromFile(parentImageFile.FullName))
                    {
                        // Creating the thumbnail and saving it 
                        // Dynamically calculating the height of the thumbnail image according to ratio
                        int height = (int)(parentImage.Height * ((double)width / (double)parentImage.Width));
                        Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);
                        thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath), parentImage.RawFormat);
                        return true;
                    }
                }
                else
                    return false;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Create thumbnail caused server error: Parameters( ");
                logText = logText.Append("parentImageFilePath -> ").Append(parentImageFilePath);
                logText = logText.Append("outputImageFilePath -> ").Append(outputImageFilePath);
                logText = logText.Append("width -> ").Append(width.ToString());
                logText = logText.Append("addSufix -> ").Append(addSufix.ToString());
                logText = logText.Append("sufix -> ").Append(sufix);
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("ImageResizer");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        /// <summary>
        /// Creates a thumbnail image from another image with the width and height
        /// specified. Helpful in case of creating a different sized thumbnail 
        /// image from the original image.
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path of the output image where to create the thumbnail. This includes the output filename.</param>
        /// <param name="height">Desired height of the thumbnail image</param>
        /// <param name="addSufix">If true, an extension is added to differentiate from the original image</param>
        /// <param name="sufix">The sufix to be be added in output filename, if not supplied, _thumb will be used.</param>
        /// <returns>True if the thumbnail is successfuly created, false otherwise</returns>
        public static bool CreateThumbnailByHeight(string parentImageFilePath, string outputImageFilePath, int height, bool addSufix, string sufix)
        {
            try
            {
                // Trying to locate the original image file
                FileInfo parentImageFile = new FileInfo(HttpContext.Current.Server.MapPath(parentImageFilePath));
                if (parentImageFile.Exists)
                {
                    if (string.IsNullOrEmpty(sufix))
                        sufix = "_thumb";

                    // Adding the sufix to the filename
                    if (addSufix)
                        outputImageFilePath = parentImageFile.Name.Insert(parentImageFile.Name.IndexOf('.') - 1, sufix);

                    // Deleting if the file already exists.
                    if (File.Exists(outputImageFilePath))
                        FileAccessUtility.DeleteFile(outputImageFilePath);

                    // Loading the image from image file
                    using (Image parentImage = Image.FromFile(parentImageFile.FullName))
                    {
                        // Creating the thumbnail and saving it 
                        // Dynamically calculating the width of the thumbnail image according to ratio
                        int width = (int)(parentImage.Height * ((double)height / (double)parentImage.Height));
                        Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);
                        thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath), parentImage.RawFormat);
                        return true;
                    }
                }
                else
                    return false;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Create thumbnail by height caused server error: Parameters( ");
                logText = logText.Append("parentImageFilePath -> ").Append(parentImageFilePath);
                logText = logText.Append("outputImageFilePath -> ").Append(outputImageFilePath);
                logText = logText.Append("height -> ").Append(height.ToString());
                logText = logText.Append("addSufix -> ").Append(addSufix.ToString());
                logText = logText.Append("sufix -> ").Append(sufix);
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("ImageResizer");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        /// <summary>
        /// Rotates and flips an image and saves in the destination folder
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path of the output image where to create the thumbnail. This includes the output filename.</param>
        /// <param name="ratioPercent">Ratio in percentage in which to set the width and height of the new image</param>
        /// <param name="angleOrDirection">Angle of rotation, or filp direction</param>
        /// <param name="addSufix">If true, an extension is added to differentiate from the original image</param>
        /// <param name="sufix">The sufix to be be added in output filename, if not supplied, _thumb will be used.</param>
        /// <returns>True if the rotated image is successfuly created, false otherwise</returns>
        public static bool RotateOrFlip(string parentImageFilePath, string outputImageFilePath, int ratioPercent,
            RotateFlipType angleOrDirection, bool addSufix, string sufix)
        {
            try
            {
                // Trying to locate the original image file
                FileInfo parentImageFile = new FileInfo(HttpContext.Current.Server.MapPath(parentImageFilePath));
                if (parentImageFile.Exists)
                {
                    if (string.IsNullOrEmpty(sufix))
                        sufix = "_thumb";

                    // Adding the sufix to the filename
                    if (addSufix)
                        outputImageFilePath = parentImageFile.Name.Insert(parentImageFile.Name.IndexOf('.') - 1, sufix);

                    // Deleting if the file already exists.
                    if (File.Exists(outputImageFilePath))
                        FileAccessUtility.DeleteFile(outputImageFilePath);

                    // Loading the image from image file
                    using (Image parentImage = Image.FromFile(parentImageFile.FullName))
                    {
                        // Calculating the width and height dynamically based
                        // on provided ratio
                        int width = (int)(parentImage.Width * ratioPercent / 100.0);
                        int height = (int)(parentImage.Height * ratioPercent / 100.0);

                        // Creating the thumbnail and saving it 
                        Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);
                        thumbnailImage.RotateFlip(angleOrDirection);
                        thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath), parentImage.RawFormat);
                        return true;
                    }
                }
                else
                    return false;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Rotate flip image caused server error: Parameters( ");
                logText = logText.Append("parentImageFilePath -> ").Append(parentImageFilePath);
                logText = logText.Append("outputImageFilePath -> ").Append(outputImageFilePath);
                logText = logText.Append("ratioPercent -> ").Append(ratioPercent.ToString());
                logText = logText.Append("angleOrDirection -> ").Append(angleOrDirection.ToString());
                logText = logText.Append("addSufix -> ").Append(addSufix.ToString());
                logText = logText.Append("sufix -> ").Append(sufix);
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("ImageResizer");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        /// <summary>
        /// Saves the image in specified format. Useful for converting one type of image into other type of image
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path of the folder where to create the new image</param>
        /// <param name="outputFormat">Format of the image file</param>
        /// <param name="sufix">user defined sufix to add in the new image</param>
        /// <returns>True if the new image is saved successfuly, false otherwise</returns>
        public static bool SaveAs(string parentImageFilePath, string outputImageFilePath, ImageFormat outputFormat)
        {
            try
            {
                // Using a temporary memory buffer to save the image in different format
                using (MemoryStream tempBuffer = new MemoryStream())
                {
                    FileInfo imageFile = new FileInfo(HttpContext.Current.Server.MapPath(parentImageFilePath));
                    if (imageFile.Exists)
                    {
                        // Loading the image from image file
                        using (Bitmap parentImage = new Bitmap(imageFile.FullName))
                        {
                            // Converting the image type and saving in buffer
                            parentImage.Save(tempBuffer, outputFormat);
                            // Writing the buffer into file
                            using (FileStream fileStream = new FileStream(HttpContext.Current.Server.MapPath(outputImageFilePath)
                                , FileMode.Create, FileAccess.Write))
                            {
                                tempBuffer.WriteTo(fileStream);
                                tempBuffer.Close();
                                tempBuffer.Dispose();
                                parentImage.Dispose();
                                return true;
                            }
                        }
                    }
                    else
                        return false;
                }
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Image save as caused server error: Parameters( ");
                logText = logText.Append("parentImageFilePath -> ").Append(parentImageFilePath);
                logText = logText.Append("outputImageFilePath -> ").Append(outputImageFilePath);
                logText = logText.Append("outputFormat -> ").Append(outputFormat.ToString());
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("ImageResizer");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path, where to create the thumbnail</param>
        /// <param name="left">Crop rectangle left pixel distance</param>
        /// <param name="top">Crop rectangle top pixel distance</param>
        /// <param name="width">Crop rectangle width</param>
        /// <param name="height">Crop rectangle height</param>
        /// <param name="addSufix">If true, a _crop extension is added to differentiate from the original image</param>
        /// <returns></returns>
        public static bool CreateCrop(string parentImageFilePath, string outputImageFilePath, int left, int top,
            int width, int height)
        {
            try
            {
                // Trying to locate the original image file
                FileInfo imageFile = new FileInfo(HttpContext.Current.Server.MapPath(parentImageFilePath));
                if (imageFile.Exists)
                {
                    // Loading the image from image file
                    using (Image parentImage = Image.FromFile(imageFile.FullName))
                    {
                        // Creating a dummy image with the width and height specified,
                        // 4th parameter should be always IntPtr.Zero
                        Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);

                        // Creating the image with the defined rectangle and saving it in file
                        using (Graphics graphics = Graphics.FromImage(thumbnailImage))
                        {
                            graphics.DrawImage(parentImage, new Rectangle(0, 0, width, height), left, top, width,
                                height, GraphicsUnit.Pixel);

                            thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath),
                                parentImage.RawFormat);
                            return true;
                        }
                    }
                }
                else
                    return false;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Image save as caused server error: Parameters( ");
                logText = logText.Append("parentImageFilePath -> ").Append(parentImageFilePath);
                logText = logText.Append("outputImageFilePath -> ").Append(outputImageFilePath);
                logText = logText.Append("left -> ").Append(left.ToString());
                logText = logText.Append("top -> ").Append(top.ToString());
                logText = logText.Append("width -> ").Append(width.ToString());
                logText = logText.Append("height -> ").Append(height.ToString());
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("ImageResizer");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                // return failure
                return false;
            }
        }
    }
}
